package com.tanhua.server.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.PageUtil;
import com.github.tobato.fastdfs.domain.conn.FdfsWebServer;
import com.github.tobato.fastdfs.domain.fdfs.StorePath;
import com.github.tobato.fastdfs.service.FastFileStorageClient;
import com.tanhua.autoconfig.template.HuanXinTemplate;
import com.tanhua.autoconfig.template.OssTemplate;
import com.tanhua.commons.utils.Constants;
import com.tanhua.dubbo.api.*;
import com.tanhua.model.domain.User;
import com.tanhua.dubbo.api.CommentApi;
import com.tanhua.dubbo.api.UserInfoApi;
import com.tanhua.dubbo.api.VideoApi;
import com.tanhua.model.domain.UserInfo;
import com.tanhua.model.mongo.Friend;
import com.tanhua.model.mongo.UserLike;
import com.tanhua.model.enums.CommentType;
import com.tanhua.model.mongo.Comment;
import com.tanhua.model.mongo.Video;
import com.tanhua.model.vo.ErrorResult;
import com.tanhua.model.vo.PageResult;
import com.tanhua.model.vo.VideoVo;
import com.tanhua.server.exception.BusinessException;
import com.tanhua.server.interceptor.UserHolder;
import lombok.extern.slf4j.Slf4j;
import org.bson.types.ObjectId;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 视频相关业务
 */
@Service
@Slf4j
public class SmallVideosService {

    @Autowired
    private FastFileStorageClient client;

    @Autowired
    private FdfsWebServer webServer;

    @Autowired
    private OssTemplate ossTemplate;

    @Autowired
    private HuanXinTemplate huanXinTemplate;

    @DubboReference
    private VideoApi videoApi;

    @DubboReference
    private UserInfoApi userInfoApi;
    @DubboReference
    private CommentApi commentApi;

    @Autowired
    private UserFreezeService userFreezeService;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private MqMessageService mqMessageService;

    @Autowired
    private MessagesService messagesService;

    @DubboReference
    private UserLikeApi userLikeApi;

    @DubboReference
    private FriendApi friendApi;

    @DubboReference
    private UserApi userApi;


    /**
     * 上传视频
     *
     * @param videoThumbnail 封面图片文件
     * @param videoFile      视频文件
     */
    public void saveVideos(MultipartFile videoThumbnail, MultipartFile videoFile) throws IOException {

        if (videoFile.isEmpty() || videoThumbnail.isEmpty()) {
            throw new BusinessException(ErrorResult.error());
        }

        //1、将视频上传到FastDFS,获取访问URL
        String filename = videoFile.getOriginalFilename();  // abc.mp4
        filename = filename.substring(filename.lastIndexOf(".") + 1);
        StorePath storePath = client.uploadFile(videoFile.getInputStream(), videoFile.getSize(), filename, null);
        String videoUrl = webServer.getWebServerUrl() + storePath.getFullPath();
        //2、将封面图片上传到阿里云OSS，获取访问的URL
        String imageUrl = ossTemplate.upload(videoThumbnail.getOriginalFilename(), videoThumbnail.getInputStream());
        //3、构建Videos对象
        Video video = new Video();
        video.setUserId(UserHolder.getUserId());
        video.setPicUrl(imageUrl);
        video.setVideoUrl(videoUrl);
        video.setText("我就是我，不一样的烟火");
        //4、调用API保存数据
        String videoId = videoApi.save(video);
        if (StringUtils.isEmpty(videoId)) {
            throw new BusinessException(ErrorResult.error());
        }

        //发送消息
        mqMessageService.sendLogMessage(UserHolder.getUserId(), "0301", "video", videoId);
    }

    //查询视频列表
    public PageResult queryVideoList(Integer page, Integer pagesize) {

        //1、查询redis数据
        String redisKey = Constants.VIDEOS_RECOMMEND + UserHolder.getUserId();
        String redisValue = redisTemplate.opsForValue().get(redisKey);
        //2、判断redis数据是否存在，判断redis中数据是否满足本次分页条数
        List<Video> list = new ArrayList<>();
        int redisPages = 0;
        if (!StringUtils.isEmpty(redisValue)) {
            //3、如果redis数据存在，根据VID查询数据
            String[] values = redisValue.split(",");
            //判断当前页的起始条数是否小于数组总数
            if ((page - 1) * pagesize < values.length) {
                List<Long> vids = Arrays.stream(values).skip((page - 1) * pagesize).limit(pagesize)
                        .map(e -> Long.valueOf(e))
                        .collect(Collectors.toList());
                //5、调用API根据PID数组查询动态数据
                list = videoApi.findMovementsByVids(vids);
            }
            redisPages = PageUtil.totalPage(values.length, pagesize);
        }
        //4、如果redis数据不存在，分页查询视频数据
        if (list.isEmpty()) {
            //page的计算规则，  传入的页码  -- redis查询的总页数
            list = videoApi.queryVideoList(page - redisPages, pagesize);  //page=1 ?
        }
        //5、提取视频列表中所有的用户id
        List<Long> userIds = CollUtil.getFieldValues(list, "userId", Long.class);
        //6、查询用户信息
        Map<Long, UserInfo> map = userInfoApi.findByIds(userIds, null);
        //7、构建返回值
        List<VideoVo> vos = new ArrayList<>();
        for (Video video : list) {
            UserInfo info = map.get(video.getUserId());
            if (info != null) {
                VideoVo vo = VideoVo.init(info, video);
                vos.add(vo);
            }
        }

        return new PageResult(page, pagesize, 0L, vos);
    }

    // 视频点赞  -- 马岩松
    public void likeById(String likeId) {
        //从redis中获取是否对该视频点赞
        // TODO: 2022/1/18 没有自定义redis字段 --李磊
        String key = Constants.VIDEOS_RECOMMEND + likeId;
        String value = Constants.VIDEO_LIKE_HASHKEY + UserHolder.getUserId();
        //  判断是否已经点赞
        if (redisTemplate.opsForHash().hasKey(key, value)) {
            // 如果已经点赞 抛出异常
            throw new BusinessException(ErrorResult.likeError());
        }
        //如果没有 更新点赞数量加一
        videoApi.update(likeId, 1);
        redisTemplate.opsForHash().put(key, value, "1");
        mqMessageService.sendLogMessage(UserHolder.getUserId(), "0301", "video", likeId);
    }

    // 取消点赞 -- 马岩松
    public void deleteId(String likeId) {
        //从redis中获取是否对该视频点赞
        String key = Constants.VIDEOS_RECOMMEND + likeId;
        String value = Constants.VIDEO_LIKE_HASHKEY + UserHolder.getUserId();
        //  判断是否已经点赞
        if (!redisTemplate.opsForHash().hasKey(key, value)) {
            // 如果已经点赞 抛出异常
            throw new BusinessException(ErrorResult.likeError());
        }
        //如果没有 更新点赞数量减一
        videoApi.update(likeId, -1);
        redisTemplate.opsForHash().delete(key, value);
    }

    //视频用户关注   南五磊
    public void focus(Long uid) {
        //获取当前用户id
        Long userId = UserHolder.getUserId();
        //查询视频用户是否喜欢当前登录用户id，返回userLike对象
        UserLike userLike = userLikeApi.findByid(uid, userId);
        //判断userLike对象为空，说明视频用户没有喜欢当前用户，那么就可以将视频用户添加到当前用户得喜欢列表中
        if (userLike != null) {
            //userLike对象不为空，说明视频用户也喜欢当前用户，调用方法将两人关系注册环信并添加进好友表中
            messagesService.contacts(uid);
        }
        //调用方法，将视频用户添加进当前用户得喜欢表中
        Boolean aBoolean = userLikeApi.saveOrUpdate(userId, uid, true);
        //判断返回值是false，抛出异常
        if (!aBoolean) {
            throw new BusinessException(ErrorResult.error());
        }
    }

    //视频用户关注 - 取消   南五磊
    public void userUnFocus(Long uid) {
        Long userId = UserHolder.getUserId();
        //查询当前用户和视频用户是否相互喜欢
        Friend friend = friendApi.findById(userId, uid);
        //判断friend对象不为空，说明当前用户与视频用户相互喜欢，
        if (friend != null) {
            User user = userApi.findById(userId);//当前用户对象
            User frienduser = userApi.findById(uid);//当前用户的好友对象
            //调用方法删除环信中当前用户与好友的关系
            Boolean aBoolean = huanXinTemplate.deleteContact(user.getHxUser(), frienduser.getHxUser());
            if (!aBoolean) {
                //删除失败，抛出异常
                throw new BusinessException(ErrorResult.error());
            }
            //删除相互喜欢表中的数据
            friendApi.delete(userId, uid);
            //调用方法删除环信中好友与当前用户的关系
            Boolean aBoolean2 = huanXinTemplate.deleteContact(frienduser.getHxUser(), user.getHxUser());
            if (!aBoolean2) {
                //删除失败，抛出异常
                throw new BusinessException(ErrorResult.error());
            }
            //删除相互喜欢表中的数据
            friendApi.delete(uid, userId);
            //需要将当前用户添加进视频用户的喜欢表中,因为相互喜欢时，当前用户取消了相互喜欢，但是好友没有取消，
            // 所以需要将好友的关系从相互喜欢表中删除后，添加进好友的喜欢表中，也就是当前用户的粉丝
            userLikeApi.saveOrUpdate(uid, userId, true);
        }
        //friend对象为空，说明是当前用户单方面喜欢视频用户 ，删除当前用户的喜欢表中的数据即可
        userLikeApi.delete(userId, uid, true);
    }

    // 评论发布  -- 马岩松
    public void saveComments(String id, String comment) {
        userFreezeService.checkUserStatus("2", UserHolder.getUserId());
        // 获取当前用户id
        Long userId = UserHolder.getUserId();
        Comment ma = new Comment();
        ma.setPublishId(new ObjectId(id));
        ma.setCommentType(CommentType.COMMENT.getType());
        ma.setContent(comment);
        ma.setUserId(userId);
        ma.setCreated(System.currentTimeMillis());
        Integer commentMa = videoApi.saveVideos(ma);
        log.info("commentMa = {}", commentMa);

    }

    // 评论点赞  -- 马岩松
    public Integer likeReview(String id) {
        Long userId = UserHolder.getUserId();
        //Comment comment = commentApi.likezan(id);
        // 从Redis中获取点赞
        String key = Constants.COMMENT_LIKE + userId;
        String value = Constants.COMMENT_LIKE_HASHKEY + id;

        // 判断redisTemplate中是否存在   存在则抛出异常    不存在点赞数量加一
        if (redisTemplate.opsForHash().hasKey(key, value)) {
            //存在则抛出异常
            throw new BusinessException(ErrorResult.likeReview());
        }
        // 不存在点赞数量加一
        Integer count = commentApi.countReview(id, 1);
        redisTemplate.opsForHash().put(key, value, "1");
        return count;
    }

    // 取消点赞  -- 马岩松
    public Integer dislikeCancel(String id) {
        Long userId = UserHolder.getUserId();
       // Comment comment = commentApi.likezan(id);
        // 从Redis中获取点赞
        String key = Constants.COMMENT_LIKE + userId;
        String value = Constants.COMMENT_LIKE_HASHKEY + id;
        // 判断redisTemplate中是否存在   存在则抛出异常    不存在则点赞数量-1
        if (!redisTemplate.opsForHash().hasKey(key, value)) {
            // 存在则抛出异常
            throw new BusinessException(ErrorResult.likeReview());
        }
        // 不存在点赞数量jian一
        Integer count = commentApi.countReview(id, -1);
        redisTemplate.opsForHash().delete(key, value);
        return count;
    }
}
